package com.bcx.wind.workflow.handler;

import com.bcx.wind.workflow.access.QueryFilter;
import com.bcx.wind.workflow.core.constant.*;
import com.bcx.wind.workflow.core.flow.NodeModel;
import com.bcx.wind.workflow.core.flow.node.ScribeTaskNode;
import com.bcx.wind.workflow.core.flow.node.TaskNode;
import com.bcx.wind.workflow.entity.WindActHistory;
import com.bcx.wind.workflow.entity.WindHistOrder;
import com.bcx.wind.workflow.entity.WindOrder;
import com.bcx.wind.workflow.entity.WindTask;
import com.bcx.wind.workflow.errorcontext.WindError;
import com.bcx.wind.workflow.interceptor.CommandContext;
import com.bcx.wind.workflow.pojo.*;
import com.bcx.wind.workflow.support.Assert;
import com.bcx.wind.workflow.support.JsonHelper;
import com.bcx.wind.workflow.support.ObjectHelper;
import com.bcx.wind.workflow.support.TimeHelper;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

import static com.bcx.wind.workflow.core.constant.NodeConfigConstant.TASK_CONTENT;
import static com.bcx.wind.workflow.core.constant.NodeConfigConstant.TASK_TYPE;
import static com.bcx.wind.workflow.core.constant.OrderVariableConstant.STRAND_APPROVE_USER;
import static com.bcx.wind.workflow.core.constant.OrderVariableConstant.TASK_APPROVE_USER;
import static com.bcx.wind.workflow.message.ErrorCode.APPROVE_USER_NOT_FOUND;

/**
 * 任务助理执行器
 *
 * @author zhanglei
 */
public class TaskHandler extends BaseHandler{

    /**
     * 当前任务配置
     */
    private WindConfig config;

    /**
     * 当前任务类型
     */
    private TaskType  curTaskType;

    /**
     * 任务审批人
     */
    private List<ApproveUser> approveUser;

    public TaskHandler(CommandContext commandContext, NodeModel curNode, Task preTask) {
        super(commandContext, curNode, preTask);
        this.config = this.preTask.getConfig();
    }

    @Override
    public void execute() {
        if(preTask.getTaskNode().inRouter() && !this.curNode.inRouter()){
            //删除子流程实例
            removeChildOrder();
        }
        //创建新任务
        buildTask();
    }




    private  void removeChildOrder(){
        QueryFilter filter = new QueryFilter()
                .setParentId(wind().getWindOrder().getId());
        List<WindOrder> childOrder = this.commandContext.access().selectOrderInstanceList(filter);
        if(!ObjectHelper.isEmpty(childOrder)){
            WindOrder order  = childOrder.get(0);
            this.commandContext.access().insertWindHistOrder(histOrder(order));
        }
        this.commandContext.access().removeOrderInstanceByParentId(this.wind().getWindOrder().getId());
    }



    private WindHistOrder histOrder(WindOrder windOrder){

        return new WindHistOrder()
                .setId(windOrder.getId())
                .setProcessId(windOrder.getProcessId())
                .setStatus(OrderStatus.complete.name())
                .setCreateUser(windOrder.getCreateUser())
                .setCreateTime(windOrder.getCreateTime())
                .setExpireTime(windOrder.getExpireTime())
                .setParentId(windOrder.getParentId())
                .setVersion(windOrder.getVersion())
                .setVariable(windOrder.getVariable())
                .setData(windOrder.getData())
                .setSystem(windOrder.getSystem())
                .setFinishTime(windOrder.getFinishTime())
                .setBusinessId(windOrder.getBusinessId())
                .setType(windOrder.getType());

    }

    private void buildTask(){
        //任务类型
        getTaskType();
        //分为创建  和 其他
        if(wind().getOperate().equals(WorkflowOperate.build)){
            buildForTask();
            return;
        }

        //审批人
        boolean createTask = false;
        List<ApproveUser> users = wind().getApproveUsers();
        this.approveUser = addApproveUser(users);
        Assert.notEmptyError(APPROVE_USER_NOT_FOUND,approveUser,wind().getWindOrder().getId());
        if(!ObjectHelper.isEmpty(approveUser)){
            for(ApproveUser user : approveUser){

                if(curNode.nodeId().equals(user.getNodeId())){
                    createTask = true;
                    Timestamp expireTime = user.getExpireTime();
                    List<WindUser> approveUsers = user.getUsers();

                    //会签
                    if(TaskType.jointly.equals(curTaskType)){
                        buildJointlyTask(approveUsers,expireTime);
                    }
                    //串签
                    else if(TaskType.strand.equals(curTaskType)){
                        buildStrandTask(approveUsers,expireTime);
                    }
                    //普通
                    else {
                        buildOrdinaryTask(approveUsers,expireTime);
                    }
                    break;
                }
            }
        }
        if(!createTask){
            WindError.error(APPROVE_USER_NOT_FOUND,null,wind().getWindOrder().getId());
        }
    }


    /**
     * 创建工作流时处理
     */
    private void buildForTask() {
        //创建任务
        WindTask task = createTask(null);
        task = commandContext.runtimeService().createNewTask(task);
        //创建履历
        createActiveHistory(task,Collections.emptyList());
        //添加到工作流实例中
        preTask.setWindTask(task);
    }




    /**
     * 提交或者退回会签处理
     */
    private void buildJointlyTask(List<WindUser> approveUser,Timestamp expireTime){
        for(WindUser user : approveUser) {
            buildOrdinaryTask(Collections.singletonList(user), expireTime);
        }
        //流程实例添加当前操作人变量
        addOrderApproveUserVariable(approveUser);
    }

    /**
     * 串签处理
     */
    private void buildStrandTask(List<WindUser> approveUser,Timestamp expireTime){
        //串签，需要先针对第一个审批人进行创建一个任务，后面继续创建
        buildOrdinaryTask(Collections.singletonList(approveUser.get(0)), expireTime);
        //添加审批人变量
        addOrderApproveUserVariable(approveUser);
        //添加串签未执行审批人变量
        addStrandVariable(approveUser);
    }

    /**
     * 在流程实例变量中添加串签审批人数据
     * @param users   串签审批人
     */
    private void addStrandVariable(List<WindUser> users){
        Object strand = this.wind().getWindOrder().variable().get(STRAND_APPROVE_USER);
        LinkedList<StrandUser>  strandUsers = new LinkedList<>();
        for(int i=0 ; i<users.size() ; i++){
            //由于第一个当前已经使用，无需保存到流程串签变量中
            if(i == 0){
                continue;
            }
            WindUser user = users.get(i);
            StrandUser u = new StrandUser()
                    .setSort(i)
                    .setUser(user);
            strandUsers.addLast(u);
        }

        if(strand == null){
            Map<String,List<StrandUser>> strandMap = new HashMap<>();
            strandMap.put(this.curNode.nodeId(),strandUsers);
            this.wind().getWindOrder().addVariable(STRAND_APPROVE_USER,strandMap);
            return;
        }

        Map<String,Object> map = JsonHelper.objectToMap(strand);
        map.put(this.curNode.nodeId(),strandUsers);
    }

    /**
     * 普通任务处理
     */
    private void buildOrdinaryTask(List<WindUser> approveUser,Timestamp expireTime){
        buildOrdinary(approveUser,expireTime);
        //流程实例添加当前操作人变量
        addOrderApproveUserVariable(approveUser);
    }

    /**
     * 普通任务处理
     */
    private void buildOrdinary(List<WindUser> approveUser,Timestamp expireTime){
        //创建任务
        WindTask task = createTask(getUserNameArray(approveUser))
                .setExpireTime(expireTime);
        task = commandContext.runtimeService().createNewTask(task);
        //创建审批人
        List<String> actors = approveUser.stream().map(WindUser::getUserId).collect(Collectors.toList());
        commandContext.runtimeService().addTaskActor(task.getId(),actors);
        //创建履历
        createActiveHistory(task,approveUser);
        //添加新的任务到当前流程任务数据中
        addNewTaskToWindCurNode(task);
    }


    /**
     * 添加新的任务到当前流程任务数据中
     */
    private void addNewTaskToWindCurNode(WindTask newTask){
        if(wind().getOperate() == WorkflowOperate.submit){
            //可以提交的任务集合
            List<Task> canSubmitTasks = preTask.getCanSubmitTasks();
            Task task = canSubmitTasks.stream().filter(t->t.getNodeId().equals(newTask.getTaskName()))
                    .findFirst().orElse(null);
            if (ObjectHelper.isEmpty(task)) {
                task = preTask;
            }
            //拷贝一个新的
            task = task.copy();
            task.setWindTask(newTask);
            //添加到任务提交数据中
            preTask.getSubmitTasks().add(task);
        }

        if(wind().getOperate() == WorkflowOperate.reject){
            //可以驳回的任务集合
            List<Task> canRejectTasks = preTask.getCanRejectTasks();
            Task task = canRejectTasks.stream().filter(t->t.getNodeId().equals(newTask.getTaskName()))
                    .findFirst().orElseThrow(()->WindError.error("reject task has not set error !"));
            //拷贝一个新的
            task = task.copy();
            task.setWindTask(newTask);
            preTask.getRejectTask().add(task);
        }
    }



    private String  getUserNameArray(List<WindUser> approveUser){
        StringBuilder builder = new StringBuilder();
        for(int i=0 ; i<approveUser.size() ; i++){
            WindUser user = approveUser.get(i);
            if(i < approveUser.size()-1) {
                builder.append(user.getUserName())
                        .append(" , ");
            }else{
                builder.append(user.getUserName());
            }
        }
        return builder.toString();
    }


    /**
     * 添加流程实例审批人变量
     * @param users   审批人数据
     */
    private void  addOrderApproveUserVariable(List<WindUser> users){
        String nodeId = this.preTask.getNodeId();
        NodeModel preNode = this.preTask.getTaskNode();
        if(preNode instanceof TaskNode){
            Map<String,Object> variable = wind().getWindOrder().variable();
            Object taskApproveUserObj = variable.get(TASK_APPROVE_USER);
            if(taskApproveUserObj == null){
                taskApproveUserObj = new HashMap<>(4);
            }
            Map<String,Object> taskApproveUser = JsonHelper.objectToMap(taskApproveUserObj);

            if(((TaskNode) preNode).isFirstTask()){
                List<WindUser> windUsers = new LinkedList<>();
                windUsers.add(user());
                taskApproveUser.put(nodeId,windUsers);
            }

            taskApproveUser.put(curNode.nodeId(),users);
            this.addOrderVariable(TASK_APPROVE_USER,taskApproveUser);
        }
    }


    /**
     * 如果审批人为空，判断当前操作是否为退回，将流程变量中退回到指定节点的审批人获取出来
     * @param approveUsers    审批人
     * @return     审批人数据
     */
    @SuppressWarnings("unchecked")
    private List<ApproveUser> addApproveUser(List<ApproveUser> approveUsers){
        if(ObjectHelper.isEmpty(approveUsers) && WorkflowOperate.reject.equals(wind().getOperate())){
            Object userObjs = wind().getWindOrder().gotVariable(TASK_APPROVE_USER);

            if (!ObjectHelper.isEmpty(userObjs)) {
                Map<String,List<WindUser>> userMaps = JsonHelper.coverObject(userObjs,Map.class,String.class,List.class);

                for(Map.Entry<String,List<WindUser>> user : userMaps.entrySet()){
                    String nodeId = user.getKey();
                    List<WindUser> users = user.getValue();
                    users = JsonHelper.coverObject(users,List.class,WindUser.class);
                    approveUsers.add(new ApproveUser().setNodeId(nodeId).addUser(users));
                }
            }
        }

        return  approveUsers;
    }


    /**
     * 创建执行历史履历
     */
    private  void   createActiveHistory(WindTask windTask,List<WindUser> approveUser){
        WindActHistory actHistory = new WindActHistory()
                .setId(ObjectHelper.primaryKey())
                .setTaskId(windTask.getId())
                .setTaskName(windTask.getTaskName())
                .setTaskDisplayName(windTask.getDisplayName())
                .setProcessId(windTask.getProcessId())
                .setOrderId(windTask.getOrderId())
                .setProcessName(wind().getWindProcess().getProcessName())
                .setProcessDisplayName(wind().getWindProcess().getDisplayName())
                .setSystem(wind().getSystem())
                .setApproveUserVariable(JsonHelper.toJson(approveUser))
                .setTaskType(windTask.getTaskType())
                .setTaskCreateUser(user().getUserId())
                .setTaskLevel(TaskLevel.main.name());
        commandContext.runtimeService().addActHistory(actHistory);
    }


    /**
     * 构建任务数据
     * @return   任务实例
     */
    private WindTask createTask(String userName){
        WindTask task =   new WindTask()
                .setId(ObjectHelper.primaryKey())
                .setTaskName(curNode.nodeId())
                .setDisplayName(curNode.nodeName())
                .setTaskType(curTaskType.name())
                .setCreateTime(TimeHelper.nowDate())
                .setApproveCount(0)
                .setStatus(TaskStatus.run.name())
                .setOrderId(wind().getWindOrder().getId())
                .setProcessId(wind().getWindProcess().getId())
                .addVariable(TASK_CONTENT,taskContent(userName))
                .setPosition(taskLink())
                .setCreateUser(user().proxyUserId())
                .setTaskLevel(TaskLevel.main.name());

        if(wind().getVars() != null){
            task.addVariable(wind().getVars());
        }
        return task;
    }


    /**
     * 获取待办内容  这里如果是流程刚开始创建 则不需要
     * @param userName  审批人
     * @return          待办内容
     */
    private String  taskContent(String  userName){
        Object object = nodeConfig().get(TASK_CONTENT);
        if(object == null && this.wind().getWindOrder().getVersion() > 1){
            //自定义组装
            return user().getUserName() + "执行操作【" + wind().getOperate()+"】关于流程【"+ wind().getWindProcess().getDisplayName()
                    +"】,表单数据【" + wind().getBusinessId() + "】等待"+userName+"审批";
        }
        if(object != null){
            return object.toString();
        }
        return null;
    }



    /**
     * 获取当前需要创建的任务类型
     */
    private void  getTaskType(){
        if(curNode instanceof TaskNode){
            TaskNode node = (TaskNode)curNode;
            TaskType type = node.jointly() ? TaskType.jointly : node.strand() ? TaskType.strand : TaskType.ordinary;

            //配置中的任务类型
            Object object = nodeConfig().get(TASK_TYPE);
            if(object != null){
                TaskType taskType = TaskType.taskType(object.toString());
                if(taskType == null){
                    this.curTaskType =  type;
                }
                type = taskType;
            }
            this.curTaskType =   type;
        }else if(curNode instanceof ScribeTaskNode){
            this.curTaskType = TaskType.ordinary;
        }
    }


}
